/*
Copyright 2008, 2009 Joonas Lehtolahti

This file is part of Openfire-C.

Openfire-C is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Openfire-C is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Openfire-C.  If not, see <http://www.gnu.org/licenses/>.
*/

int XfireAnalyze_hLoginSalt(XFINST inst, struct XfirePacket *packet) {
	/* Login salt from server
	 * http://xfireplus.com/xfwiki/index.php/Packet_80_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT non0string*
	#define _XFABP salt_value
	
	non0string *salt_value = XfirePacketGetStringAttribute(packet, (unsigned const char *)"salt");
	
	if (salt_value) {
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* no internal handling */
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	/* Nothing to clean up */
	
	return retval;
}

int XfireAnalyze_hInvalidLogin(XFINST inst, struct XfirePacket *packet) {
	/* Login failed
	 * http://xfireplus.com/xfwiki/index.php/Packet_81_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT unsigned int
	#define _XFABP *reason_value
	
	unsigned int *reason_value = XfirePacketGetIntegerAttribute(packet, (unsigned const char *)"reason");
	
	if (reason_value) {
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* no internal handling */
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	/* Nothing to clean up */
	
	return retval;
}

int XfireAnalyze_hClientInfo(XFINST inst, struct XfirePacket *packet) {
	/* The client's information received
	 * http://xfireplus.com/xfwiki/index.php/Packet_82_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT unsigned int, non0string*
	#define _XFABP *userid_value, sid_value
	
	unsigned int *userid_value = XfirePacketGetIntegerAttribute(packet, (unsigned const char *)"userid");
	non0string *sid_value = XfirePacketGetStringAttribute(packet, (unsigned const char *)"sid");
	non0string *nick_value = XfirePacketGetStringAttribute(packet, (unsigned const char *)"nick");
	
	if (userid_value && sid_value && nick_value) {
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* internal handling */
		if (retval & XFIH_HANDLED) {
			n0sfree(inst->self->sid);
			inst->self->userid = *userid_value;
			inst->self->sid = n0scopy(sid_value);
			inst->self->nickname = n0scopy(nick_value);
		}
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	
	return retval;
}

int XfireAnalyze_hWrongVersion(XFINST inst, struct XfirePacket *packet) {
	/* Client logged in with too old version and is told to update
	 * http://xfireplus.com/xfwiki/index.php/Packet_86_00
	 * 
	 * SINGLE LIST CALLBACKS
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT LinkedList*, unsigned int
	#define _XFABP update_list, *flags_value
	
	LinkedList *version_list = XfirePacketGetListAttribute(packet, (unsigned const char *)"version");
	LinkedList *file_list = XfirePacketGetListAttribute(packet, (unsigned const char *)"file");
	LinkedList *command_list = XfirePacketGetListAttribute(packet, (unsigned const char *)"command");
	LinkedList *fileid_list = XfirePacketGetListAttribute(packet, (unsigned const char *)"fileid");
	unsigned int *flags_value = XfirePacketGetIntegerAttribute(packet, (unsigned const char *)"flags");
	
	if (version_list && file_list && command_list && fileid_list && flags_value) {
		if (version_list->nodes == file_list->nodes && file_list->nodes == command_list->nodes &&
			command_list->nodes == fileid_list->nodes) {
			LinkedList *update_list = LLcreate();
			
			ListNode *version_node = version_list->first;
			ListNode *file_node = file_list->first;
			ListNode *command_node = command_list->first;
			ListNode *fileid_node = fileid_list->first;
			
			while (version_node) {
				struct_alloc(update, XfVersionUpdate);
				update->version = *(unsigned int*)version_node->x;
				update->fileurl = (non0string*)file_node->x;
				update->command = *(unsigned int*)command_node->x;
				update->fileid = *(unsigned int*)fileid_node->x;
				
				LLaddLast(update_list, update);
				
				NEXT_NODE(version_node);
				NEXT_NODE(file_node);
				NEXT_NODE(command_node);
				NEXT_NODE(fileid_node);
			}
			/* include external handlers calling */
			#include "XfirePacketAnalyzeExt.inc"
			
			/* no internal handling */
			LLdelete(update_list, (FREEFUNC*)free);
		}
		else {
			/* Different length of lists */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all lists found */
		retval = XFIH_UNKNOWN;
	}
	/* Delete lists, but not the data in them!
	 * The data is direct pointers to the data in the XfirePacket which
	 * will be deleted along with this data later!
	 */
	LLdelete(fileid_list, NULL);
	LLdelete(command_list, NULL);
	LLdelete(file_list, NULL);
	LLdelete(version_list, NULL);
	
	return retval;
}

int XfireAnalyze_hPrefs(XFINST inst, struct XfirePacket *packet) {
	/* Client preferences
	 * http://xfireplus.com/xfwiki/index.php/Packet_8d_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT unsigned int
	#define _XFABP newprefs
	
	struct XfirePacket *prefspack = XfirePacketGetPacketAttribute(packet, SHORT_ATTRIBUTE(\x4c));
	
	if (prefspack) {
		int attr_index = 0;
		unsigned int newprefs = XfireDefaultPreferences(0);
		for (; attr_index < prefspack->attrs; attr_index++) {
			struct XfirePattr *attr = prefspack->attributes[attr_index];
			unsigned char prefid = *(attr->name->s);
			non0string *value = (non0string*)(attr->attr);
			if (*(value->s) == '0') {
				XFP_DEL_PREF(newprefs, prefid);
			}
			else if (*(value->s) == '1') {
				XFP_SET_PREF(newprefs, prefid);
			}
			else {
				/* Unknown preferences value! */
				retval |= XFIH_UNKNOWN;
			}
		}
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* internal handling */
		if (retval & XFIH_HANDLED) {
			inst->prefs = newprefs;
		}
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	/* Nothing to clean up */
	
	return retval;
}

int XfireAnalyze_hMyScreenshots(XFINST inst, struct XfirePacket *packet) {
	/* List of screenshots on profile page
	 * http://xfireplus.com/xfwiki/index.php/Packet_9d_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT LinkedList*
	#define _XFABP screenshot_list
	
	LinkedList *index_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x5c));
	LinkedList *gameid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x21));
	LinkedList *gameip_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x22));
	LinkedList *gameport_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x23));
	LinkedList *text_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x54));
	LinkedList *time_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x50));
	LinkedList *locked_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x5d));
	LinkedList *guid_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x5e));
	LinkedList *filesize_list = XfirePacketGetListAttribute(packet, SHORT_ATTRIBUTE(\x55));
	
	if (index_list && gameid_list && gameip_list && gameport_list && text_list && time_list && locked_list && guid_list && filesize_list) {
		if (index_list->nodes == gameid_list->nodes && gameid_list->nodes == gameip_list->nodes && gameip_list->nodes == gameport_list->nodes &&
		  gameport_list->nodes == text_list->nodes && text_list->nodes == time_list->nodes && time_list->nodes == locked_list->nodes &&
		  locked_list->nodes == guid_list->nodes && guid_list->nodes == filesize_list->nodes) {
		  	
		  	LinkedList *screenshot_list = LLcreate();
		  	
			ListNode *index_node = index_list->first;
			ListNode *gameid_node = gameid_list->first;
			ListNode *gameip_node = gameip_list->first;
			ListNode *gameport_node = gameport_list->first;
			ListNode *text_node = text_list->first;
			ListNode *time_node = time_list->first;
			ListNode *locked_node = locked_list->first;
			ListNode *guid_node = guid_list->first;
			ListNode *filesize_node = filesize_list->first;
			struct XfScreenshotInfo *xfs;
			
			while (index_node) {
				xfs = XfireScreenshotInfo();
				xfs->index = *(unsigned int*)index_node->x;
				xfs->game = XfireGameData(*(unsigned int*)gameid_node->x,
					*(unsigned int*)gameip_node->x,
					*(unsigned int*)gameport_node->x);
				xfs->description = n0scopy((non0string*)text_node->x);
				xfs->guid = n0scopy((non0string*)guid_node->x);
				xfs->timestamp = *(unsigned int*)time_node->x;
				xfs->locked = *(unsigned int*)locked_node->x;
				xfs->filesize = *(unsigned int*)filesize_node->x;
				
				LLaddLast(screenshot_list, xfs);
				
				NEXT_NODE(index_node);
				NEXT_NODE(gameid_node);
				NEXT_NODE(gameip_node);
				NEXT_NODE(gameport_node);
				NEXT_NODE(text_node);
				NEXT_NODE(time_node);
				NEXT_NODE(locked_node);
				NEXT_NODE(guid_node);
				NEXT_NODE(filesize_node);
			}
			
			/* include external handlers calling */
			#include "XfirePacketAnalyzeExt.inc"
			
			/* internal handling */
			if (retval & XFIH_HANDLED) {
				LLdelete(inst->self->extdata->screenshots, (FREEFUNC*)FreeXfireScreenshotInfo);
				inst->self->extdata->screenshots = screenshot_list;
			}
			else {
				/* discard new screenshots */
				LLdelete(screenshot_list, (FREEFUNC*)FreeXfireScreenshotInfo);
			}
		}
		else {
			/* Different length of lists */
			retval = XFIH_UNKNOWN;
		}
	}
	else {
		/* Not all lists found */
		retval = XFIH_UNKNOWN;
	}
	/* Delete lists, but not the data in them!
	 * The data is direct pointers to the data in the XfirePacket which
	 * will be deleted along with this data later!
	 */
	LLdelete(filesize_list, NULL);
	LLdelete(guid_list, NULL);
	LLdelete(locked_list, NULL);
	LLdelete(time_list, NULL);
	LLdelete(text_list, NULL);
	LLdelete(gameport_list, NULL);
	LLdelete(gameip_list, NULL);
	LLdelete(gameid_list, NULL);
	LLdelete(index_list, NULL);
	
	return retval;
}

int XfireAnalyze_hConnectIP(XFINST inst, struct XfirePacket *packet) {
	/* Client connected to old server IP address
	 * http://xfireplus.com/xfwiki/index.php/Packet_af_00
	 */
	unsigned int retval = XFIH_HANDLED;
	
	/* define external handler function type and calling parameters */
	#define _XFABT unsigned int
	#define _XFABP *newip_value
	
	unsigned int *newip_value = XfirePacketGetIntegerAttribute(packet, SHORT_ATTRIBUTE(\x38));
	
	if (newip_value) {
		/* include external handlers calling */
		#include "XfirePacketAnalyzeExt.inc"
		
		/* no internal handling */
	}
	else {
		/* Not all attributes found */
		retval = XFIH_UNKNOWN;
	}
	
	return retval;
}
